#include <stdio.h>      // For fprintf, snprintf
#include <stdlib.h>     // For exit
#include <string.h>     // For strcmp
#include <fcntl.h>      // For open, O_* flags
#include <unistd.h>     // For read, write, close, ftruncate (needed for mmap target)
#include <dirent.h>     // For DIR, struct dirent, opendir, readdir, closedir
#include <sys/stat.h>   // For mkdir, fstat (needed for mmap source size)
#include <sys/mman.h>   // For mmap, munmap
#include <limits.h>     // For PATH_MAX

// 定义一个合适的缓冲区大小 (仅 read/write 方法需要)
#define BUFFER_SIZE (64 * 1024) // 64KB

// 函数：拷贝单个普通文件
// 学生需要在此函数内实现具体的拷贝逻辑 (read/write 或 mmap)
int copy_regular_file(const char *source_path, const char *dest_path) {
    int source_fd = -1; // Initialize to -1
    int dest_fd = -1;   // Initialize to -1
    int result = -1;    // Default to failure
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read;
    ssize_t bytes_written;

    // 1. 打开源文件 (只读)
    source_fd = open(source_path, O_RDONLY);
    if (source_fd == -1) {
        fprintf(stderr, "Error opening source file: %s\n", source_path);
        return -1; // Early exit on failure
    }

    // 2. 打开/创建目标文件 (读写模式，以便后续 mmap 或 write)
    //    使用默认权限 0644
    dest_fd = open(dest_path, O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (dest_fd == -1) {
        fprintf(stderr, "Error opening destination file: %s\n", dest_path);
        close(source_fd); // Clean up already opened source_fd
        return -1;
    }

    // --------------------------------------------------------------------
    // TODO: 在这里实现文件拷贝的核心逻辑
    //
    // 你可以选择以下两种方法之一来实现：
    //
    // 方法 A: 使用 read/write
    //   a. 定义一个缓冲区 (char buffer[BUFFER_SIZE];)
    //   b. 使用循环:
    //      i.  从 source_fd 读取数据到 buffer (read())
    //      ii. 如果读取成功 (返回值 > 0)，则将 buffer 中的数据写入 dest_fd (write())
    //          - 注意处理 write 可能未完全写入的情况，需要内层循环确保写完
    //      iii.如果读取到文件末尾 (返回值 == 0)，则跳出循环
    //      iv. 如果读取出错 (返回值 < 0)，则处理错误
    //   c. 检查最终的读取状态
    //
    // 方法 B: 使用 mmap
    //   a. 获取源文件大小 (fstat())
    //   b. 调整目标文件大小 (ftruncate()) 使其与源文件一致
    //   c. 将源文件映射到内存 (mmap() with PROT_READ, MAP_PRIVATE)
    //   d. 将目标文件映射到内存 (mmap() with PROT_READ | PROT_WRITE, MAP_SHARED)
    //   e. 使用内存拷贝函数 (如 memcpy()) 将源映射区内容拷贝到目标映射区
    //   f. 解除两个文件的内存映射 (munmap())
    //   g. 检查各步骤返回值处理错误
    //
    // --------------------------------------------------------------------
    while ((bytes_read = read(source_fd, buffer, BUFFER_SIZE)) > 0) {
	bytes_written = 0;
	while (bytes_written < bytes_read){
	    ssize_t written = write(dest_fd, buffer + bytes_written,bytes_read - bytes_written);
	    if(written == -1){
		fprintf(stderr, "Error writing to destination file: %s\n",dest_path);
		goto cleanup;
	    }
	    bytes_written += written;
	}
    }

    if(bytes_read == -1) {
	fprintf(stderr, "Error reading source file:%s\n",source_path);
	goto cleanup;
    }
    // 模拟成功，学生需要根据实际实现修改返回值
    result = 0; // 假设成功，学生需要根据拷贝逻辑设置
cleanup:
    // 3. 关闭文件描述符 (无论成功或失败，只要已打开)
    if (source_fd != -1) {
        close(source_fd);
    }
    if (dest_fd != -1) {
        close(dest_fd);
    }
    return result;
}


int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <source_task_dir> <destination_dir>\n", argv[0]);
        return 1;
    }

    const char *source_task_dir = argv[1];
    const char *destination_dir = argv[2];
    DIR *dir;
    struct dirent *entry;
    int overall_result = 0; // 跟踪是否有任何失败

    // 尝试创建目标目录 (如果不存在) - 简化处理，依赖外部脚本清理
    // 注意：如果目标目录已存在但不是目录，这里不会报错，但后续 open 会失败
    mkdir(destination_dir, 0755); // 忽略返回值，假设 run_and_time.sh 会处理

    // 打开源目录
    dir = opendir(source_task_dir);
    if (dir == NULL) {
        fprintf(stderr, "Error opening source directory: %s\n", source_task_dir);
        return 1;
    }

    // 遍历源目录中的条目
    while ((entry = readdir(dir)) != NULL) {
        // 跳过 "." 和 ".."
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        // 假设目录内都是普通文件，直接构建路径并拷贝
        char source_entry_path[PATH_MAX];
        char dest_entry_path[PATH_MAX];

        // 构建源文件完整路径
        snprintf(source_entry_path, PATH_MAX, "%s/%s", source_task_dir, entry->d_name);
        // 构建目标文件完整路径
        snprintf(dest_entry_path, PATH_MAX, "%s/%s", destination_dir, entry->d_name);

        // 拷贝文件
        // printf("Copying file: %s -> %s\n", source_entry_path, dest_entry_path); // 可选进度
        if (copy_regular_file(source_entry_path, dest_entry_path) == -1) {
            fprintf(stderr, "Failed to copy file: %s\n", source_entry_path);
            overall_result = -1; // 标记失败
        }
    }

    closedir(dir);

    if (overall_result != 0) {
        // fprintf(stderr, "Copy process encountered errors.\n"); // 脚本会报告命令失败
        return 1; // 返回错误码
    }

    return 0; // 成功
}
